/*
 * Copyright 2024 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.pajamas.daydream.serializer.json;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

import org.pajamas.protocol.Builder;

/**
 * @author william
 * @since 2022/12/31
 */

public final class Jsons {

    /**
     * default behavior: reserve null values
     */
    public static final JacksonJson NO_OP;

    /**
     * format prettily
     */
    public static final JacksonJson PRETTY;

    static {
        NO_OP = builder().build();
        PRETTY = builder().outputPrettily().outputOrderByKey().build();
    }

    public static JsonBuilder builder() {
        return new JsonBuilder();
    }

    public static class JsonBuilder implements Builder<JacksonJson> {
        private final transient ObjectMapper mapper;

        private JsonBuilder() {
            this.mapper = new ObjectMapper();
        }

        public JacksonJson build() {
            return new JacksonJson(this.mapper);
        }

        /**
         * default behavior: compress text
         *
         * @return JsonBuilder
         */
        public JsonBuilder outputPrettily() {
            this.mapper.enable(SerializationFeature.INDENT_OUTPUT);
            return this;
        }

        /**
         * Date,Calendar output as source style, likes 2022-12-31T05:24:38.309+00:00
         * (default behavior: long as timestamp)
         *
         * @return JsonBuilder
         */
        public JsonBuilder outputDateAsString() {
            this.mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
            return this;
        }

        /**
         * ignores null values
         */
        public JsonBuilder outputNullIgnored() {
            this.mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
            return this;
        }

        /**
         * ignores:
         * - null values
         * - array
         * - collection
         */
        public JsonBuilder outputEmptyIgnored() {
            this.mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
            return this;
        }

        public JsonBuilder outputOrderByKey() {
            this.mapper.enable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS);
            return this;
        }

        public JsonBuilder inputBlankStringAsNull() {
            this.mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
            return this;
        }

        public JsonBuilder inputEmptyArrayAsNull() {
            this.mapper.enable(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT);
            return this;
        }

        /**
         * causes closing input, as unknown properties found
         *
         * @return JsonBuilder
         */
        public JsonBuilder inputUnknownPropertiesSuppressed() {
            this.mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
            return this;
        }

        /**
         * allow single quotes
         *
         * @return JsonBuilder
         */
        public JsonBuilder inputSingleQuotesAllowed() {
            this.mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, Boolean.TRUE);
            return this;
        }
    }
}
